Skip to content

feat(cli)(#32): canonical UX — --json, --help, asset-pair input, auto-help on errors#33

Merged
vrogojin merged 1 commit into
mainfrom
feat/issue-32-ux-canonical
Jun 5, 2026
Merged

feat(cli)(#32): canonical UX — --json, --help, asset-pair input, auto-help on errors#33
vrogojin merged 1 commit into
mainfrom
feat/issue-32-ux-canonical

Conversation

@vrogojin
Copy link
Copy Markdown
Contributor

@vrogojin vrogojin commented Jun 5, 2026

Closes #32.

No more legacy. All should be canonical.

Issue #32 asked for sphere-cli UX consistency across five concrete goals.
This PR delivers all five passes as a clean break — no backwards-compat
shims for the legacy quoted-asset form or for the JSON-by-default output.

What changed

Pass A — output formatting

  • New formatOutput(payload, shape, label?) helper with a typed
    OutputShape union and per-shape renderers (identity, invoice-terms,
    invoice-status, transfer-result, swap-status, swap-ping, auto-return,
    invoice-transfers, generic, …).
  • Global --json flag opts back into JSON; default is a human-readable
    labelled block.
  • Replaced 22 console.log(JSON.stringify(...)) sites. File-write /
    POST-body JSON.stringify calls remain (wire format).

Pass B — canonical asset input

  • Dropped parseAssetArg (quoted compound form, "10 UCT").
  • New consumeAssetPair(args, startIdx) reads two argv tokens.
  • invoice-create, invoice-return, swap-propose now take
    --asset <amount> <coin>, --offer <amount> <coin>, --want <amount> <coin>.
  • invoice-create supports multiple --asset flags for multi-asset
    invoices.

Pass C — --help works for every command/subcommand

  • Early-dispatch shim in main() catches --help / -h before the
    switch, handling sub-subcommand keys (wallet create, daemon start)
    via compound lookup with fallback to top-level.
  • src/index.ts: legacy subcommands disable commander's built-in
    --help (helpOption(false)) so the flag reaches our dispatcher.
  • help added to LEGACY_NAMESPACES so sphere help <cmd> routes
    through the COMMAND_HELP registry.
  • Universal flags (--json, --help/-h) shown in every help block.

Pass D — completion + docs

  • Added COMMAND_HELP entries for completions and help so the
    drift-guard test passes.
  • README: new "UX — canonical conventions" + "Shell completion"
    sections documenting the canonical syntax and three install paths
    (no-sudo, system-wide, per-user zsh fpath).

Pass E — auto-help on invalid input

  • Single failWithHelp(cmdName, errorMsg) helper prints
    Error: <msg> followed by the full COMMAND_HELP block to stderr,
    then exit(1).
  • Replaced ~40 console.error('Usage: …'); process.exit(1) sites.
  • New resolveInvoiceId() helper collapses the duplicated
    invoice-prefix lookup boilerplate across ~10 invoice-* commands.

Static UX guard

New src/legacy/legacy-cli-ux.test.ts enforces the invariants so
future drift surfaces as a test failure:

  1. No stray console.log(JSON.stringify(...)) in the dispatch body.
  2. No console.error('Usage: …'); process.exit(…) legacy stubs.
  3. No parseAssetArg(...) call sites.
  4. Every COMMAND_HELP key is reachable through the completion list.
  5. Helpers (formatOutput, failWithHelp, consumeAssetPair) exist.
  6. --json and --help shims are wired in main().

Verification

npx tsc --noEmit            # clean
npx vitest run              # 113/113 pass (incl. 7 new UX guard tests)
npx tsup                    # build clean

Smoke-tested in dev:

  • sphere invoice create --help → prints the new canonical help block
  • sphere swap propose --help → canonical --offer <amount> <coin> form
  • sphere help send → routes through COMMAND_HELP['send']
  • sphere payments send (no args) → Error: … + full help block + exit 1
  • sphere wallet init integration test compatibility: human render
    keeps l1Address/directAddress/chainPubkey as labels so the
    existing toMatch(/l1Address/) assertion still passes.

Breaking changes (intentional — "no more legacy")

  • The quoted compound asset form (--asset "10 UCT") is no longer
    accepted. Use --asset 10 UCT (two positional tokens).
  • Default output is human-friendly, not raw JSON. Scripts that scrape
    CLI stdout must pass --json.

Both are explicitly called out in the new "UX — canonical conventions"
README section so the migration path is one place.

Out of scope (per the issue)

  • Cosmetic redesign (colors, ASCII art).
  • Migrating off the legacy-cli.ts monolith — that's its own refactor;
    this PR lands within the existing file structure as the issue
    permits.
  • Daemon-mode command output formatting (separate UX surface).

…-help on errors

Issue #32 — sphere-cli UX consistency. No more legacy: every command
takes the same input shape, defaults to human-friendly output, and
prints the full help block (never a one-line "Usage:" stub) on errors.

Five-pass implementation (legacy-cli.ts):

Pass A — Output formatting
  - New formatOutput(payload, shape, label?) helper with a typed
    OutputShape union and per-shape renderers (identity, invoice-terms,
    invoice-status, transfer-result, swap-status, etc.).
  - Global --json flag (jsonMode) opts back into JSON; default is a
    human-readable labelled block.
  - Replaced 22 console.log(JSON.stringify(...)) sites in the dispatch
    body. File-write/POST-body JSON.stringify calls remain (wire format).

Pass B — Canonical asset input
  - Dropped parseAssetArg (quoted compound form, "10 UCT").
  - New consumeAssetPair(args, startIdx) reads two argv tokens.
  - invoice-create, invoice-return, swap-propose all take
    --asset <amount> <coin>, --offer <amount> <coin>, --want <amount> <coin>.
  - invoice-create now supports multiple --asset flags for multi-asset
    invoices.

Pass C — --help works everywhere
  - Early-dispatch shim in main() catches --help/-h before the switch,
    handling sub-subcommand keys ("wallet create", "daemon start") via
    compound lookup with fallback to top-level.
  - src/index.ts: legacy subcommands disable commander's built-in
    --help (helpOption(false)) so the flag reaches our dispatcher.
  - "help" added to LEGACY_NAMESPACES so `sphere help <cmd>` routes
    through the COMMAND_HELP registry.
  - Universal flags (--json, --help/-h) added to printCommandHelp output.

Pass D — Completion + docs
  - Added COMMAND_HELP entries for `completions` and `help` so the
    drift-guard test passes.
  - README: new "UX — canonical conventions" + "Shell completion"
    sections documenting the canonical syntax and three install paths
    (no-sudo, system-wide, per-user zsh fpath).

Pass E — Auto-help on invalid input
  - Single failWithHelp(cmdName, errorMsg) helper prints "Error: <msg>"
    followed by the full COMMAND_HELP block to stderr, then exit(1).
  - Replaced ~40 `console.error('Usage: …'); process.exit(1)` sites.
  - New helper resolveInvoiceId() collapses the duplicated
    invoice-prefix lookup boilerplate across ~10 invoice-* commands.

Plus a new src/legacy/legacy-cli-ux.test.ts that statically guards the
invariants (no stray JSON.stringify, no "Usage:" stubs, no parseAssetArg
calls, completion ↔ COMMAND_HELP alignment) so future drift surfaces as
a test failure.

Verified: typecheck clean, 113/113 tests pass (incl. 7 new UX guard
tests), build clean, smoke-tested `sphere invoice create --help`,
`sphere swap propose --help`, `sphere help send`, and the missing-args
auto-help path on `sphere payments send`.
@vrogojin vrogojin force-pushed the feat/issue-32-ux-canonical branch from c2c8771 to 310c981 Compare June 5, 2026 11:13
@vrogojin vrogojin merged commit 946ff48 into main Jun 5, 2026
2 checks passed
@vrogojin vrogojin deleted the feat/issue-32-ux-canonical branch June 5, 2026 11:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sphere-cli UX consistency: unified currency input, human-friendly default output, complete --help, autocomplete, auto-help on invalid input

1 participant